﻿#ifndef __INC_QG_OPENGL_ES2_H__
#define __INC_QG_OPENGL_ES2_H__

#ifdef _MSC_VER
#pragma once
#endif

#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#if _MSC_VER	// ANGLE
#	pragma comment(lib, "libEGL")
#	pragma comment(lib, "libGLESv2")
#endif

//
#define GLdouble						GLfloat
#define GL_CLAMP						GL_CLAMP_TO_EDGE
#define GL_WRITE_ONLY					GL_WRITE_ONLY_OES
#define GL_READ_WRITE					0			// ES2는 읽기 안됨
#define GL_READ_ONLY					0			// ES2는 읽기 안됨
#define GL_BGRA							GL_BGRA_EXT 
#define GL_LUMINANCE16F					0x881E
#define GL_LUMINANCE32F					0x8818
#define GL_RGBA16F						0x881A
#define GL_RGBA32F						0x8814
#define GL_UNSIGNED_INT_8_8_8_8_REV		GL_UNSIGNED_BYTE
#define GL_HALF_FLOAT					GL_HALF_FLOAT_OES
#define GL_UNSIGNED_INT_24_8			GL_UNSIGNED_INT_24_8_OES
#define GL_RGBA16F_EXT					0x881A
#define GL_MIN							GL_MIN_EXT
#define GL_MAX							GL_MAX_EXT
#define GL_TEXTURE_BASE_LEVEL			0x813C		// 안씀
#define GL_TEXTURE_MAX_LEVEL			0x813D		// 안씀
#define GL_TEXTURE_ENV					0x2300		// 안씀
#define GL_TEXTURE_ENV_MODE				0x2200		// 안씀
#define GL_TEXTURE_ENV_COLOR			0x2201		// 안씀
#define GL_MODULATE						0x2100		// 안씀
#define GL_DECAL						0x2101		// 안씀
#define GL_POINT						0x1B00		// 안씀
#define GL_LINE							0x1B01		// 안씀
#define GL_FILL							0x1B02		// 안씀
#define GL_COMPARE_REF_TO_TEXTURE		0x884E
#define GL_PIXEL_UNPACK_BUFFER			0x88EC
#define GL_PIXEL_PACK_BUFFER			0x88EB
#define GL_TEXTURE_WRAP_R				GL_TEXTURE_WRAP_R_OES
#define GL_TEXTURE_LOD_BIAS				0x8501
#define GL_TEXTURE_COMPARE_FUNC			0x884D
#define GL_TEXTURE_COMPARE_MODE			0x884C
#define glTexEnvf(a,b,c)

//
#if _SB_ANDROID_
typedef void (GL_APIENTRYP PFNGLGENQUERIESEXTPROC) (GLsizei n, GLuint *ids);
typedef void (GL_APIENTRYP PFNGLDELETEQUERIESEXTPROC) (GLsizei n, const GLuint *ids);
typedef GLboolean(GL_APIENTRYP PFNGLISQUERYEXTPROC) (GLuint id);
typedef void (GL_APIENTRYP PFNGLBEGINQUERYEXTPROC) (GLenum target, GLuint id);
typedef void (GL_APIENTRYP PFNGLENDQUERYEXTPROC) (GLenum target);
typedef void (GL_APIENTRYP PFNGLGETQUERYIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTUIVEXTPROC) (GLuint id, GLenum pname, GLuint *params);
#endif

//
#define QGES2_ENTRYPOINT_LIST(decl) \
	decl(PFNEGLCREATEIMAGEKHRPROC, eglCreateImageKHR) \
	decl(PFNEGLDESTROYIMAGEKHRPROC, eglDestroyImageKHR) \
	/*decl(PFNEGLPOSTSUBBUFFERNVPROC, eglPostSubBufferNV)*/ \
	decl(PFNEGLGETSYSTEMTIMENVPROC, eglGetSystemTimeNV) \
	decl(PFNEGLCREATESYNCKHRPROC, eglCreateSyncKHR) \
	decl(PFNEGLDESTROYSYNCKHRPROC, eglDestroySyncKHR) \
	decl(PFNEGLCLIENTWAITSYNCKHRPROC, eglClientWaitSyncKHR) \
	decl(PFNGLEGLIMAGETARGETTEXTURE2DOESPROC, glEGLImageTargetTexture2DOES) \
	decl(PFNGLDELETEFENCESNVPROC, glDeleteFencesNV) \
	decl(PFNGLGENFENCESNVPROC, glGenFencesNV) \
	decl(PFNGLGETFENCEIVNVPROC, glGetFenceivNV) \
	decl(PFNGLISFENCENVPROC, glIsFenceNV) \
	decl(PFNGLFINISHFENCENVPROC, glFinishFenceNV) \
	decl(PFNGLSETFENCENVPROC, glSetFenceNV) \
	decl(PFNGLTESTFENCENVPROC, glTestFenceNV) \
	decl(PFNGLMAPBUFFEROESPROC, glMapBufferOES) \
	decl(PFNGLUNMAPBUFFEROESPROC, glUnmapBufferOES) \
	decl(PFNGLGETBUFFERPOINTERVOESPROC, glGetBufferPointervOES)
#define QGES2_ENTRYPOINT_LIST_OCCLUSION(decl) \
	decl(PFNGLGENQUERIESEXTPROC, glGenQueriesEXT) \
	decl(PFNGLDELETEQUERIESEXTPROC, glDeleteQueriesEXT) \
	decl(PFNGLISQUERYEXTPROC, glIsQueryEXT) \
	decl(PFNGLBEGINQUERYEXTPROC, glBeginQueryEXT) \
	decl(PFNGLENDQUERYEXTPROC, glEndQueryEXT) \
	decl(PFNGLGETQUERYIVEXTPROC, glGetQueryivEXT) \
	decl(PFNGLGETQUERYOBJECTUIVEXTPROC, glGetQueryObjectuivEXT)

#define QGES2_DECL_ENTRYPOINT(type,func) extern type func;
QGES2_ENTRYPOINT_LIST(QGES2_DECL_ENTRYPOINT);
QGES2_ENTRYPOINT_LIST_OCCLUSION(QGES2_DECL_ENTRYPOINT);

// 
#include "qg_opengl.h"

//
struct qbOpenGLES2 : public qbOpenGLBase
{
	static void QglInitializeExtensions(const char* extstr);
	static bool QglTestExtensions();

	K_FORCEINLINE static bool QglSupportATITC() { return qgl_support_atitc; }
	K_FORCEINLINE static bool QglSupportBGRA8888() { return qgl_support_bgra8888; }
	K_FORCEINLINE static bool QglSupportColorBufferHalfFloat() { return qgl_support_color_buffer_half_float; }
	K_FORCEINLINE static bool QglSupportCopyImage() { return qgl_support_copy_image; }
	K_FORCEINLINE static bool QglSupportDepthStencilAttachment() { return false; }
	K_FORCEINLINE static bool QglSupportDepthTexture() { return qgl_support_depth_texture; }
	K_FORCEINLINE static bool QglSupportDXT() { return qgl_support_s3tc; }
	K_FORCEINLINE static bool QglSupportHalfFloat() { return qgl_support_half_float; }
	K_FORCEINLINE static bool QglSupportMapBuffer() { return qgl_support_map_buffer; }
	K_FORCEINLINE static bool QglSupportMultiOffScreen() { return false; }
	K_FORCEINLINE static bool QglSupportMultisampledTexture() { return false; }
	K_FORCEINLINE static bool QglSupportOcclusion() { return qgl_support_occlusion; }
	K_FORCEINLINE static bool QglSupportPackedDepthStencil() { return qgl_support_packed_depth_stencil; }
	K_FORCEINLINE static bool QglSupportPolygonMode() { return false; }
	K_FORCEINLINE static bool QglSupportPVRTC() { return qgl_support_pvrtc; }
	K_FORCEINLINE static bool QglSupportRGBA8() { return qgl_support_rgba8; }
	K_FORCEINLINE static bool QglSupportSRGB() { return qgl_support_srgb; }
	K_FORCEINLINE static bool QglSupportTexture3D() { return false; }
	K_FORCEINLINE static bool QglSupportTextureBaseLevel() { return false; }
	K_FORCEINLINE static bool QglSupportTextureCubeLOD() { return false; }
	K_FORCEINLINE static bool QglSupportTextureFloat() { return qgl_support_texture_float; }
	K_FORCEINLINE static bool QglSupportTextureHalfFloat() { return qgl_support_texture_half_float; }
	K_FORCEINLINE static bool QglSupportTextureLODBias() { return false; }
	K_FORCEINLINE static bool QglSupportTextureNPOT() { return qgl_support_texture_npot; }
	K_FORCEINLINE static bool QglSupportTextureParameter() { return true; }
	K_FORCEINLINE static bool QglSupportTextureMaxLevel() { return false; }

	// 기본
	K_FORCEINLINE static void QglClearDepth(GLdouble Depth)
	{
		glClearDepthf(Depth);
	}

	K_FORCEINLINE static void QglDepthRange(GLdouble Near, GLdouble Far)
	{
		glDepthRangef(Near, Far);
	}

	// 텍스쳐
	K_FORCEINLINE static void QglActiveTexture(GLenum texture)
	{
		glActiveTexture(texture);
	}

	K_FORCEINLINE static void QglCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data)
	{
		glCompressedTexSubImage2D(target, level, 0, 0, width, height, internalformat, imageSize, data);
	}

	K_FORCEINLINE static void QglGenerateMipmap(GLenum target)
	{
		glGenerateMipmap(target);
	}

	// 블렌드
	K_FORCEINLINE static void QglBlendEquation(GLenum mode)
	{
		glBlendEquation(mode);
	}

	K_FORCEINLINE static void QglBlendEquationi(GLuint index, GLenum mode)
	{
		glBlendEquation(mode);
	}

	K_FORCEINLINE static void QglBlendEquationSeparatei(GLuint index, GLenum modeRGB, GLenum modeAlpha)
	{
		glBlendEquationSeparate(modeRGB, modeAlpha);
	}

	K_FORCEINLINE static void QglBlendFunc(GLenum src, GLenum dst)
	{
		glBlendFunc(src, dst);
	}

	K_FORCEINLINE static void QglBlendFunci(GLuint index, GLenum src, GLenum dst)
	{
		glBlendFunc(src, dst);
	}

	K_FORCEINLINE static void QglBlendFuncSeparatei(GLuint index, GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha)
	{
		glBlendFuncSeparate(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha);
	}

	K_FORCEINLINE static void QglColorMaski(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a)
	{
		glColorMask(r, g, b, a);
	}

	K_FORCEINLINE static void QglEnableIndexed(GLenum target, GLuint index)
	{
		k_assert_0(target == GL_BLEND);
		glEnable(target);
	}

	K_FORCEINLINE static void QglDisableIndexed(GLenum target, GLuint index)
	{
		k_assert_0(target == GL_BLEND);
		glDisable(target);
	}

	// 레이아웃	
	K_FORCEINLINE static void QglEnableVertexArray(GLuint index)
	{
		glEnableVertexAttribArray(index);
	}

	K_FORCEINLINE static void QglDisableVertexArray(GLuint index)
	{
		glDisableVertexAttribArray(index);
	}

	K_FORCEINLINE static void QglVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* pointer)
	{
		glVertexAttribPointer(index, size, type, normalized, stride, pointer);
	}

	// FBO
	K_FORCEINLINE static void QglGenFramebuffers(GLsizei n, GLuint* framebuffers)
	{
		glGenFramebuffers(n, framebuffers);
	}

	K_FORCEINLINE static void QglBindFramebuffer(GLenum target, GLuint framebuffer)
	{
		glBindFramebuffer(target, framebuffer);
	}

	K_FORCEINLINE static void QglDeleteFramebuffers(GLsizei n, const GLuint* framebuffers)
	{
		glDeleteFramebuffers(n, framebuffers);
	}

	K_FORCEINLINE static GLenum QglCheckFramebufferStatus(GLenum target)
	{
		return glCheckFramebufferStatus(target);
	}

	K_FORCEINLINE static void QglFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
	{
		k_assert_0(attachment == GL_COLOR_ATTACHMENT0 || attachment == GL_DEPTH_ATTACHMENT);
		glFramebufferTexture2D(target, attachment, textarget, texture, level);
	}

	K_FORCEINLINE static void QglGenRenderbuffers(GLsizei n, GLuint* renderbuffers)
	{
		glGenRenderbuffers(n, renderbuffers);
	}

	K_FORCEINLINE static void QglBindRenderbuffer(GLenum target, GLuint renderbuffer)
	{
		glBindRenderbuffer(target, renderbuffer);
	}

	K_FORCEINLINE static void QglDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers)
	{
		glDeleteRenderbuffers(n, renderbuffers);
	}

	K_FORCEINLINE static void QglRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
	{
		glRenderbufferStorage(target, internalformat, width, height);
	}

	K_FORCEINLINE static void QglFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
	{
		glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);
	}

	K_FORCEINLINE static void QglGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params)
	{
		glGetRenderbufferParameteriv(target, pname, params);
	}

	K_FORCEINLINE static void QglGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params)
	{
		glGetFramebufferAttachmentParameteriv(target, attachment, pname, params);
	}

	// 프로그램과 세이더
	K_FORCEINLINE static GLuint QglCreateProgram(void)
	{
		return glCreateProgram();
	}

	K_FORCEINLINE static void QglDeleteProgram(GLuint object)
	{
		glDeleteProgram(object);
	}

	K_FORCEINLINE static void QglAttachShader(GLuint program, GLuint shader)
	{
		glAttachShader(program, shader);
	}

	K_FORCEINLINE static void QglDetachShader(GLuint program, GLuint shader)
	{
		glDetachShader(program, shader);
	}

	K_FORCEINLINE static void QglGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)
	{
		glGetAttachedShaders(program, maxcount, count, shaders);
	}

	K_FORCEINLINE static void QglGetProgramiv(GLuint program, GLenum type, GLint* param)
	{
		glGetProgramiv(program, type, param);
	}

	K_FORCEINLINE static void QglGetProgramInfoLog(GLuint program, GLsizei maxLength, GLsizei* length, GLchar* infoLog)
	{
		glGetProgramInfoLog(program, maxLength, length, infoLog);
	}

	K_FORCEINLINE static void QglGetActiveAttrib(GLuint program, GLuint index, GLsizei maxlength, GLsizei* length, GLint* size, GLenum* type, GLchar* name)
	{
		glGetActiveAttrib(program, index, maxlength, length, size, type, name);
	}

	K_FORCEINLINE static void QglGetActiveUniform(GLuint program, GLuint index, GLsizei maxlength, GLsizei* length, GLint* size, GLenum* type, GLchar* name)
	{
		glGetActiveUniform(program, index, maxlength, length, size, type, name);
	}

	K_FORCEINLINE static GLint QglGetAttribLocation(GLuint program, const GLchar *name)
	{
		return glGetAttribLocation(program, name);
	}

	K_FORCEINLINE static GLint QglGetUniformLocation(GLuint program, const GLchar* name)
	{
		return glGetUniformLocation(program, name);
	}

	K_FORCEINLINE static GLuint QglCreateShader(GLenum shaderType)
	{
		return glCreateShader(shaderType);
	}

	K_FORCEINLINE static void QglShaderSource(GLuint shader, GLsizei numOfStrings, const char** strings, const GLint* lengths)
	{
		glShaderSource(shader, numOfStrings, strings, lengths);
	}

	K_FORCEINLINE static void QglCompileShader(GLuint shader)
	{
		glCompileShader(shader);
	}

	K_FORCEINLINE static void QglLinkProgram(GLuint program)
	{
		glLinkProgram(program);
	}

	K_FORCEINLINE static void QglUseProgram(GLuint prog)
	{
		glUseProgram(prog);
	}

	K_FORCEINLINE static void QglDeleteShader(GLuint shader)
	{
		glDeleteShader(shader);
	}

	K_FORCEINLINE static void QglGetShaderiv(GLuint shader, GLenum type, GLint* param)
	{
		glGetShaderiv(shader, type, param);
	}

	K_FORCEINLINE static void QglGetShaderInfoLog(GLuint shader, GLsizei maxLength, GLsizei* length, GLchar* infoLog)
	{
		glGetShaderInfoLog(shader, maxLength, length, infoLog);
	}

	K_FORCEINLINE static void QglUniform1fv(GLint loc, GLsizei count, const GLfloat* v)
	{
		glUniform1fv(loc, count, v);
	}

	K_FORCEINLINE static void QglUniform2fv(GLint loc, GLsizei count, const GLfloat* v)
	{
		glUniform2fv(loc, count, v);
	}

	K_FORCEINLINE static void QglUniform3fv(GLint loc, GLsizei count, const GLfloat* v)
	{
		glUniform3fv(loc, count, v);
	}

	K_FORCEINLINE static void QglUniform4fv(GLint loc, GLsizei count, const GLfloat* v)
	{
		glUniform4fv(loc, count, v);
	}

	K_FORCEINLINE static void QglUniform1iv(GLint loc, GLsizei count, const GLint* v)
	{
		glUniform1iv(loc, count, v);
	}

	K_FORCEINLINE static void QglUniform2iv(GLint loc, GLsizei count, const GLint* v)
	{
		glUniform2iv(loc, count, v);
	}

	K_FORCEINLINE static void QglUniform3iv(GLint loc, GLsizei count, const GLint* v)
	{
		glUniform3iv(loc, count, v);
	}

	K_FORCEINLINE static void QglUniform4iv(GLint loc, GLsizei count, const GLint* v)
	{
		glUniform4iv(loc, count, v);
	}

	K_FORCEINLINE static void QglUniformMatrix2fv(GLint loc, GLsizei count, GLboolean transpose, const GLfloat* v)
	{
		glUniformMatrix2fv(loc, count, transpose, v);
	}

	K_FORCEINLINE static void QglUniformMatrix3fv(GLint loc, GLsizei count, GLboolean transpose, const GLfloat* v)
	{
		glUniformMatrix3fv(loc, count, transpose, v);
	}

	K_FORCEINLINE static void QglUniformMatrix4fv(GLint loc, GLsizei count, GLboolean transpose, const GLfloat* v)
	{
		glUniformMatrix4fv(loc, count, transpose, v);
	}

	// 버퍼
	K_FORCEINLINE static void QglGenBuffers(GLsizei n, GLuint* buffers)
	{
		glGenBuffers(n, buffers);
	}

	K_FORCEINLINE static void QglBindBuffer(GLenum target, GLuint buffer)
	{
		glBindBuffer(target, buffer);
	}

	K_FORCEINLINE static void QglDeleteBuffers(GLsizei n, const GLuint* buffers)
	{
		glDeleteBuffers(n, buffers);
	}

	K_FORCEINLINE static void QglBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)
	{
		glBufferData(target, size, data, usage);
	}

	K_FORCEINLINE static void QglBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
	{
		glBufferSubData(target, offset, size, data);
	}

	K_FORCEINLINE static void* QglMapBuffer(GLenum target, GLenum access)
	{
		return glMapBufferOES(target, access);
	}

	K_FORCEINLINE static GLboolean QglUnmapBuffer(GLenum target)
	{
		return glUnmapBufferOES(target);
	}

	K_FORCEINLINE static GLboolean QglIsBuffer(GLuint buffer)
	{
		return glIsBuffer(buffer);
	}

	// 스텐실
	K_FORCEINLINE static void QglStencilFuncSeparate(GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask)
	{
		glStencilFuncSeparate(frontfunc, backfunc, ref, mask);
	}

	K_FORCEINLINE static void QglStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
	{
		glStencilOpSeparate(face, fail, zfail, zpass);
	}

	// 오클루전
	K_FORCEINLINE static void QglGenQueries(GLsizei n, GLuint* ids)
	{
		glGenQueriesEXT(n, ids);
	}

	K_FORCEINLINE static void QglDeleteQueries(GLsizei n, const GLuint* ids)
	{
		glDeleteQueriesEXT(n, ids);
	}

	K_FORCEINLINE static GLboolean QglIsQuery(GLuint id)
	{
		return glIsQueryEXT(id); 
	}

	K_FORCEINLINE static void QglBeginQuery(GLenum target, GLuint id)
	{
		glBeginQueryEXT(target, id);
	}

	K_FORCEINLINE static void QglEndQuery(GLenum target)
	{
		glEndQueryEXT(target);
	}

	K_FORCEINLINE static void QglGetQueryiv(GLenum target, GLenum pname, GLint* params)
	{
		glGetQueryivEXT(target, pname, params);
	}

	K_FORCEINLINE static void QglGetQueryObjectuiv(GLuint id, GLenum pname, GLuint* params)
	{
		glGetQueryObjectuivEXT(id, pname, params);
	}

	// 기타
	K_FORCEINLINE static void QglSwapInterval(kpointer display, int interval)
	{
		eglSwapInterval((EGLDisplay)display, interval);
	}


	K_FORCEINLINE static bool QglSwapBuffers(kpointer display, kpointer surface)
	{
		EGLDisplay d = (EGLDisplay)display;
		EGLSurface s = (EGLSurface)surface;

		if (d == NULL || !eglSwapBuffers(d, s))
		{
			if (s == NULL)
				return false;
			else
			{
				if (eglGetError() == EGL_CONTEXT_LOST)
				{
					// 이거 종료해야하나
				}
			}

			return false;
		}

		return true;
	}

protected:
	static bool qgl_support_atitc;						// GL_AMD_COMPRESSED_ATC_TEXTURE / GL_ATI_TEXTURE_COMPRESSION_ATITC
	static bool qgl_support_bgra8888;					// GL_APPLE_TEXTURE_FORMAT_BGRA8888
	static bool qgl_support_occlusion;					// GL_ARB_OCCLUSION_QUERY2 / GL_EXT_OCCLUSION_QUERY_BOOLEAN
	static bool qgl_support_color_buffer_half_float;	// GL_EXT_COLOR_BUFFER_HALF_FLOAT
	static bool qgl_support_srgb;						// GL_EXT_SRGB
	static bool qgl_support_s3tc;						// GL_EXT_TEXTURE_COMPRESSION_S3TC / GL_NV_TEXTURE_COMPRESSION_S3TC
	static bool qgl_support_pvrtc;						// GL_IMG_TEXTURE_COMPRESSION_PVRTC
	static bool qgl_support_depth_texture;				// GL_OES_DEPTH_TEXTURE
	static bool qgl_support_map_buffer;					// GL_OES_MAPBUFFER
	static bool qgl_support_rgba8;						// GL_OES_RGB8_RGBA8
	static bool qgl_support_half_float;					// GL_OES_VERTEX_HALF_FLOAT
	static bool qgl_support_texture_float;				// GL_OES_TEXTURE_FLOAT
	static bool qgl_support_texture_half_float;			// GL_OES_TEXTURE_HALF_FLOAT
	static bool qgl_support_texture_npot;				// GL_OES_TEXTURE_NPOT
	static bool qgl_support_packed_depth_stencil;		// GL_OES_PACKED_DEPTH_STENCIL
};

//
typedef qbOpenGLES2 qbOpenGL;

#endif // !__INC_QG_OPENGL_ES2_H__
